package com.xiaomaoguai.fcp.pre.kepler.router.async.delay;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import com.xiaomaoguai.fcp.pre.kepler.router.async.delay.strategy.DefaultStrategy;
import com.xiaomaoguai.fcp.pre.kepler.router.async.delay.strategy.RetryStrategy;
import com.xiaomaoguai.fcp.pre.kepler.router.async.delay.strategy.StrategyManager;

import java.io.Serializable;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Getter
@Setter
public class RetryInfo implements Serializable {

	private static final long serialVersionUID = -7596105205399607808L;

	private String msgId = UUID.randomUUID().toString();

	private RetryStrategy retryStrategy = new DefaultStrategy();// 延时策略

	private Long startTime;// 执行时间

	private Long interval = 15 * 1000L;// 间隔时间

	private Long maxRetryTimes = 5L;// 最大回调次数 -1无上限

	private int retryTimes = 1; // 当前重试次数

	public void retryStrategy(String retryStrategy) {
		if (StringUtils.isNoneBlank(retryStrategy))
			this.retryStrategy = StrategyManager.create(retryStrategy, interval, maxRetryTimes);
	}

	public RetryInfo interval(String interval) {
		if (StringUtils.isNoneBlank(interval))
			this.interval = Long.valueOf(interval);
		startTime = System.currentTimeMillis() + this.interval;
		return this;
	}

	public RetryInfo maxretryTimes(String maxRetryTimes) {
		if (StringUtils.isNoneBlank(maxRetryTimes))
			this.maxRetryTimes = Long.valueOf(maxRetryTimes);
		return this;
	}

	public RetryInfo nextTime() {
		retryTimes += 1;
		interval = retryStrategy.interval(retryTimes);
		startTime = System.currentTimeMillis() + interval;
		return this;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + retryTimes;
		result = prime * result + (int) (startTime ^ (startTime >>> 32));
		result = prime * result + ((msgId == null) ? 0 : msgId.hashCode());
		return result;
	}

	public boolean isEnd() {
		return maxRetryTimes == -1L ? false : retryTimes > maxRetryTimes;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RetryInfo other = (RetryInfo) obj;
		if (msgId == null) {
			if (other.getMsgId() != null)
				return false;
		} else if (!msgId.equals(other.getMsgId()))
			return false;
		return true;
	}

	public int compareTo(RetryInfo other) {
		if (other == this) {
			return 0;
		}
		if (other instanceof RetryInfo) {
			RetryInfo otherRetry = (RetryInfo) other;
			long otherStartTime = otherRetry.getStartTime();
			return (int) (this.startTime - otherStartTime);
		}
		return 0;
	}

	public long getDelay(TimeUnit unit) {
		return unit.convert(startTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
	}

}
